package tw.com.hitevision.whiteboard.android.widgets;

import android.app.Activity;
import android.app.ActivityManager;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import java.io.File;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

import androidx.annotation.Nullable;
import tw.com.hitevision.whiteboard.android.BuildConfig;
import tw.com.hitevision.whiteboard.android.Props;
import tw.com.hitevision.whiteboard.android.R;
import tw.com.hitevision.whiteboard.android.andServer.NetUtils;
import tw.com.hitevision.whiteboard.android.andServer.OnServerChangeListener;
import tw.com.hitevision.whiteboard.android.andServer.ServerPresenter;
import tw.com.hitevision.whiteboard.android.andServer.ServerService;
import tw.com.hitevision.whiteboard.android.navigator.Item;
import tw.com.hitevision.whiteboard.android.storage.FileHelper;
import tw.com.hitevision.whiteboard.android.util.FileShareUtils;
import tw.com.hitevision.whiteboard.android.util.GlideApp;
import tw.com.hitevision.whiteboard.android.util.GlideRequests;

import static android.content.Context.ACTIVITY_SERVICE;

public class NavigatorViewQRCodeDownloadDialog implements DialogInterface {

    private String TAG = NavigatorViewQRCodeDownloadDialog.class.getSimpleName();
    private Context context;
    private Dialog dialog;
    private NavigatorViewQRCodeExportDialog.FileFormat fileFormat;
//    private int exportFileFormat;
    private List<String> fileNameList = new ArrayList<>();
    private ServerPresenter serverPresenter;
    private GlideRequests glideRequests;
    private ProgressBar progressBar;
    private ImageView qrCodeImageView, alertIcon;
    private TextView titleText, contentText, alertTitle, alertContent, alertTryAgain, outsideTitle;
    private Handler handler;
    private String timeStamp;
    private File saveFolder;
    private View share;
    private Activity activity;
    private String screenshotFolderPath;

    public NavigatorViewQRCodeDownloadDialog(Activity activity, Handler handler) {
        dialog = new Dialog(activity, R.style.ExportDialog);
//        this.context = context;
        this.activity = activity;
        this.handler = handler;
//        this.exportFileFormat = exportFileFormat;
//        for(Item item: itemList) {
//            fileNameList.add(item.getPreviewFile());
//        }
        if(Props.getFlavorChipset().equals(Props.Flavor.Chipset.Hisi)){
            screenshotFolderPath = FileHelper.FOLDER_SCREENSHOTS_19C;
        }else{
            screenshotFolderPath = FileHelper.FOLDER_SCREENSHOTS;
        }
        if(Props.getMainboardVersion() == Props.Mainboard.V_828 && BuildConfig.BUILD_TYPE.equals("release")) {
            saveFolder = new File("/storage/sdcard0/" + screenshotFolderPath);
        } else {
            saveFolder = new File(Environment.getExternalStorageDirectory().getPath() + screenshotFolderPath);
        }
    }

    void setData(List<String> fileNameList,NavigatorViewQRCodeExportDialog.FileFormat fileFormat) {
        this.fileNameList = fileNameList;
        this.fileFormat = fileFormat;
    }

    void show() {
        dialog.setContentView(R.layout.navigator_qrcode_export_download_dialog);
        // 811 dialog adjustment position
        if(Props.isFake4k()) {
            WindowManager.LayoutParams layoutParams = Objects.requireNonNull(dialog.getWindow()).getAttributes();
            layoutParams.setTitle("ist_win_editdialog");
            dialog.getWindow().setAttributes(layoutParams);
        }
        Objects.requireNonNull(dialog.getWindow()).setGravity(Gravity.CENTER);
        Objects.requireNonNull(dialog.getWindow()).setLayout(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);
        dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
        dialog.getWindow().setDimAmount(0.5f);
        dialog.setCanceledOnTouchOutside(true);
        dialog.setCancelable(true);
        dialog.setOnCancelListener(dialogInterface -> cancel());
        dialog.setOnDismissListener(dialogInterface -> dismiss());
        outsideTitle = dialog.findViewById(R.id.navigator_qrcode_export_retitle);
        switch (fileFormat) {
            case PDF: {
                outsideTitle.setText(R.string.options_export_export_as_pdf);
                break;
            }
            case PNG: {
                outsideTitle.setText(R.string.options_export_export_as_png);
                break;
            }
            case JPEG: {
                outsideTitle.setText(R.string.options_export_export_as_jpeg);
                break;
            }
        }
        titleText = dialog.findViewById(R.id.navigator_qrcode_export_download_title);
        View close = dialog.findViewById(R.id.navigator_qrcode_export_download_close);
        close.setOnClickListener(view -> cancel());
        qrCodeImageView = dialog.findViewById(R.id.navigator_qrcode_export_download_qrcode_view);
        progressBar = dialog.findViewById(R.id.navigator_qrcode_export_download_progressbar);
        contentText = dialog.findViewById(R.id.navigator_qrcode_export_download_content);
        serverPresenter = new ServerPresenter(activity, new OnServerChangeListener() {
            @Override
            public void onServerStarted(String ipAddress) {
                Log.d(TAG, "onServerStarted ipAddress:" + ipAddress);
                showSuccessUI(ipAddress);
            }

            @Override
            public void onServerStopped() {
                Log.d(TAG, "onServerStopped");
                showFailUI();
            }

            @Override
            public void onServerError(String errorMessage) {
                Log.d(TAG, "onServerError message:" + errorMessage);
                if(checkServiceRunning()) {
                    if(getCurrentIPAddress()!=null) {
                        Log.d(TAG, "ipAddress:" + getCurrentIPAddress());
                        showSuccessUI(getCurrentIPAddress());
                    } else {
                        showFailUI();
                    }
                } else {
                    showFailUI();
                }
            }
        });
        alertIcon = dialog.findViewById(R.id.navigator_qrcode_export_alert_icon);
        alertTitle = dialog.findViewById(R.id.navigator_qrcode_export_alert_title);
        alertContent = dialog.findViewById(R.id.navigator_qrcode_export_alert_content);
        alertTryAgain = dialog.findViewById(R.id.navigator_qrcode_export_alert_try_again);
        alertTryAgain.setOnClickListener(view -> {
            showProgressingUI();
            Calendar calendar = Calendar.getInstance();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddhhmmss", Locale.US);
            timeStamp = simpleDateFormat.format(calendar.getTime());
            serverPresenter.startServer(activity, new ArrayList<>(fileNameList), fileFormat, timeStamp);
        });

        share = dialog.findViewById(R.id.button_share);
        share.setOnClickListener(v -> {
            FileHelper fileHelper = FileHelper.getInstance(activity);
            ArrayList<String> files = new ArrayList<>();
            Log.d(TAG, "onClick: fileformat: "+fileFormat.toString());
            switch (fileFormat) {
                case PNG:
                    for (String name : fileNameList) {
                        File file = fileHelper.getPreviewFile(name);
                        if (file.exists()) {
                            files.add(file.toString());
                        } else {
                            Log.d(TAG, "PNG file is not exist. path:" + file.getPath());
                        }
                    }
                    break;
                case JPEG:
                    for (String fileName : fileNameList) {
                        String name = fileName.substring(0, fileName.lastIndexOf("."));
                        File file = fileHelper.getPreviewFile(name + ".jpeg");
                        if (file.exists()) {
                            files.add(file.toString());
                        } else {
                            Log.d(TAG, "JPEG file is not exist. path:" + file.getPath());
                        }
                    }
                    break;
                case PDF:
                    File file = new File(saveFolder, String.format("/image/%s.pdf", timeStamp));
                    if (file.exists()) {
                        files.add(file.toString());
                    } else {
                        Log.d(TAG, "PDF file is not exist. path:" + file.getPath());

                    }
                    break;
                default:
                    break;
            }
            if(files.size() > 0) {
                Intent intent = FileShareUtils.createShareIntent(activity, files);
                if (intent != null) {
//                        activity.startActivityForResult(intent,MainActivity.REQUEST_SHARER);
                    activity.startActivity(intent);
                } else {
                    Log.e(TAG, "Sharer app not installed!");
                }
            } else {
                showFailUI();
//                    listener.showExportErrorDialog(activity.getString(R.string.navigator_error_dialog_title), activity.getString(R.string.navigator_error_dialog_description), activity.getString(R.string.navigator_dialog_ok));
            }
        });

        showProgressingUI();
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddhhmmss", Locale.US);
        timeStamp = simpleDateFormat.format(calendar.getTime());
        serverPresenter.startServer(activity, new ArrayList<>(fileNameList), fileFormat, timeStamp);

        glideRequests = GlideApp.with(activity.getApplicationContext());

        dialog.show();
    }

    @Override
    public void cancel() {
        if(dialog.isShowing()) {
            dialog.cancel();
        }
    }

    @Override
    public void dismiss() {
        serverPresenter.stopServer(activity);
        serverPresenter.unregister(activity);
        if(dialog.isShowing()) {
            dialog.dismiss();
        }
    }

    private Bitmap getQRCode(String IPAddress) {
        return Create2DCode("http://" + IPAddress + ":" + NetUtils.PORT_SERVER +"/download.html", 500, 500);
    }

    private Bitmap Create2DCode(String str, int width, int height) {
        try {
            Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
            hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            hints.put(EncodeHintType.MARGIN, 1);
            BitMatrix matrix = new QRCodeWriter().encode(str, BarcodeFormat.QR_CODE, width, height);
            matrix = deleteWhite(matrix);
            width = matrix.getWidth();
            height = matrix.getHeight();
            int[] pixels = new int[width * height];
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    if (matrix.get(x, y)) {
                        pixels[y * width + x] = Color.BLACK;
                    } else {
                        pixels[y * width + x] = Color.WHITE;
                    }
                }
            }
            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
            return bitmap;
        } catch (Exception e) {
            return null;
        }
    }

    private BitMatrix deleteWhite(BitMatrix matrix) {
        int[] rec = matrix.getEnclosingRectangle();
        int resWidth = rec[2] + 1;
        int resHeight = rec[3] + 1;

        BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);
        resMatrix.clear();
        for (int i = 0; i < resWidth; i++) {
            for (int j = 0; j < resHeight; j++) {
                if (matrix.get(i + rec[0], j + rec[1]))
                    resMatrix.set(i, j);
            }
        }
        return resMatrix;
    }

    private void showProgressingUI() {
        titleText.setVisibility(View.VISIBLE);
        progressBar.setVisibility(View.VISIBLE);
        qrCodeImageView.setVisibility(View.VISIBLE);
        contentText.setVisibility(View.VISIBLE);
        alertIcon.setVisibility(View.GONE);
        alertTitle.setVisibility(View.GONE);
        alertContent.setVisibility(View.GONE);
        alertTryAgain.setVisibility(View.GONE);
    }

    private void showSuccessUI(String ipAddress) {
        titleText.setVisibility(View.VISIBLE);
        progressBar.setVisibility(View.VISIBLE);
        qrCodeImageView.setVisibility(View.VISIBLE);
        contentText.setVisibility(View.VISIBLE);
        alertIcon.setVisibility(View.GONE);
        alertTitle.setVisibility(View.GONE);
        alertContent.setVisibility(View.GONE);
        alertTryAgain.setVisibility(View.GONE);

        if(ipAddress.equals(getCurrentIPAddress()) && isNetworkConnected()) {
            Bitmap qRCodeBitmap = getQRCode(ipAddress);
            glideRequests.load(qRCodeBitmap)
                    .downsample(DownsampleStrategy.CENTER_INSIDE)
                    .listener(new RequestListener<Drawable>() {
                        @Override
                        public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
                            showFailUI();
                            return false;
                        }

                        @Override
                        public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
                            progressBar.setVisibility(View.GONE);
                            return false;
                        }
                    })
                    .centerInside()
                    .into(qrCodeImageView);
        } else {
            showFailUI();
        }
    }

    private String getTitleText(NavigatorViewQRCodeExportDialog.FileFormat fileFormat) {
        switch (fileFormat) {
            case PNG:
                return String.valueOf(activity.getResources().getText(R.string.qrcode_export_as_png));
            case JPEG:
                return String.valueOf(activity.getResources().getText(R.string.qrcode_export_as_jpeg));
            case PDF:
                return String.valueOf(activity.getResources().getText(R.string.qrcode_export_as_pdf));
            default:
                return "";
        }
    }

    private void showFailUI() {
        titleText.setVisibility(View.GONE);
        progressBar.setVisibility(View.GONE);
        qrCodeImageView.setVisibility(View.GONE);
        contentText.setVisibility(View.GONE);
        alertIcon.setVisibility(View.VISIBLE);
        alertTitle.setVisibility(View.VISIBLE);
        alertContent.setVisibility(View.VISIBLE);
        alertTryAgain.setVisibility(View.VISIBLE);
    }

    private String getCurrentIPAddress() {
        try {
            for (Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
                NetworkInterface networkInterface = (NetworkInterface) en.nextElement();
                for (Enumeration enumeration = networkInterface.getInetAddresses(); enumeration.hasMoreElements();) {
                    InetAddress inetAddress = (InetAddress) enumeration.nextElement();
                    if (!inetAddress.isLoopbackAddress()&&inetAddress instanceof Inet4Address) {
                        return inetAddress.getHostAddress();
                    }
                }
            }
            return null;
        } catch (Exception exception) {
            Log.d(TAG, "exception:" + exception);
            return null;
        }
    }


    private boolean checkServiceRunning(){
        ActivityManager manager = (ActivityManager)activity.getSystemService(ACTIVITY_SERVICE);
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (ServerService.class.getName().equals(service.service.getClassName())) {
                return true;
            }
        }
        return false;
    }

    private boolean isNetworkConnected() {
        boolean haveConnectedWifi = false;
        boolean haveConnectedMobile = false;
        boolean wiredNetworkConnected;
        boolean wifiConnected;
        boolean netWorkConnected;
        ConnectivityManager cm = (ConnectivityManager)activity.getSystemService(activity.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetworkInfo = cm.getActiveNetworkInfo();
        wiredNetworkConnected = activeNetworkInfo != null && activeNetworkInfo.isConnected();
        NetworkInfo[] netInfo = cm.getAllNetworkInfo();
        for (NetworkInfo ni : netInfo) {
            if (ni.getTypeName().equalsIgnoreCase("WIFI")) {
                if (ni.isConnected()) {
                    haveConnectedWifi = true;
                }
            }
            if (ni.getTypeName().equalsIgnoreCase("MOBILE")) {
                if (ni.isConnected()) {
                    haveConnectedMobile = true;
                }
            }
        }
        wifiConnected = haveConnectedWifi || haveConnectedMobile;
        netWorkConnected = wiredNetworkConnected || wifiConnected;
        return netWorkConnected;
    }
}
